`ifndef RESET_DRIVER__SV
    `define RESET_DRIVER__SV

    typedef class reset_trans;
    typedef class reset_driver;

    class reset_driver_callbacks extends uvm_callback;

        virtual task pre_reset_cbk( reset_driver xactor, reset_trans tr);

            `uvm_info("RESET_CBK","Calling Pre-reset callback",UVM_HIGH)
      

        endtask: pre_reset_cbk


        // Called after a Reset has been executed
        virtual task post_reset_cbk( reset_driver xactor,
            reset_trans tr);
            `uvm_info("POST_RESET_CBK","Calling Pre-reset callback",UVM_HIGH)

        endtask: post_reset_cbk

    endclass: reset_driver_callbacks


    class reset_driver extends uvm_driver # (reset_trans);
   
        typedef virtual wb_master_if v_if; 
        v_if drv_if;
        `uvm_register_cb(reset_driver,reset_driver_callbacks); 
   
        extern function new(string name = "reset_driver",
            uvm_component parent = null); 
   
        `uvm_component_utils(reset_driver)

        extern virtual function void connect_phase(uvm_phase phase);
        extern virtual function void end_of_elaboration_phase(uvm_phase phase);
        extern virtual task run_phase(uvm_phase phase);
        extern protected virtual task tx_driver();

    endclass: reset_driver


    function reset_driver::new(string name = "reset_driver",
        uvm_component parent = null);
        super.new(name, parent);

      
    endfunction: new



    function void reset_driver::connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        uvm_config_db#(v_if)::get(this, "", "mst_if", drv_if); 
    endfunction: connect_phase

    function void reset_driver::end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        if (drv_if == null)
            `uvm_fatal("NO_CONN", "Virtual port not connected to the actual interface instance");   
    endfunction: end_of_elaboration_phase

   

    task reset_driver::run_phase(uvm_phase phase);
        super.run_phase(phase);
        fork 
            tx_driver();
        join_none
    endtask: run_phase


    task reset_driver::tx_driver();
        forever begin
            reset_trans tr;
            `uvm_info("RESET_DRIVER", "Starting transaction...",UVM_LOW)
            seq_item_port.get_next_item(tr);
            `uvm_info("RESET_DRIVER", tr.sprint(),UVM_HIGH)

            `uvm_do_callbacks(reset_driver,reset_driver_callbacks, pre_reset_cbk(this, tr))
            case (tr.reset_kind) 
                reset_trans::ASSERT: begin
                    drv_if.master_cb.DAT_O <= 'bz;
                    drv_if.master_cb.TGD_O <= 'bz;
                    drv_if.master_cb.ADR_O  <= 'bz;
                    drv_if.master_cb.WE_O   <= 'bz;
                    drv_if.master_cb.CYC_O <= 'bz;
                    drv_if.master_cb.LOCK_O <= 'bz;
                    drv_if.master_cb.SEL_O <= 'bz;
                    drv_if.master_cb.STB_O <= 'bz;
                    drv_if.master_cb.TGA_O <= 'bz;
                    drv_if.master_cb.TGC_O <= 'bz;
                    drv_if.master_cb.RST_O <= 'b1;
                    repeat(tr.cycles) @(drv_if.master_cb);

                end
                reset_trans::DEASSERT: begin
                    drv_if.master_cb.RST_O <= 'b0;
                    repeat(tr.cycles) @(drv_if.master_cb);

                end
            endcase
            `uvm_do_callbacks(reset_driver,reset_driver_callbacks, post_reset_cbk(this, tr))
            `uvm_info("RESET_DRIVER", "Completed transaction...",UVM_LOW)
            seq_item_port.item_done();

        end // Forever
    endtask : tx_driver

`endif // RESET_DRIVER__SV


